package gorm

import (
	"errors"
	"gitee.com/molonglove/goboot/gorm/utils"
)

// Namespace SQL模板
func (db *DB) Namespace(name string) (tx *DB) {
	tx = db.getInstance()
	if item, ok := tx.Mapper[name]; ok {
		tx.Statement.Mapper = item
		return tx
	}
	tx.Error = errors.New("模板不存在")
	return tx
}

func (db *DB) Template(sqlId string, param ...any) (tx *DB) {
	return db.sql(sqlId, "select", param...)
}

// DQuery 获取动态SQL的查询模板
func (db *DB) DQuery(sqlId string, param ...any) (tx *DB) {
	var (
		sql *DynamicNode
		ok  bool
	)
	tx = db.getInstance()
	if sql, ok = tx.Statement.Mapper.Nodes[Select][sqlId]; !ok {
		tx.Error = errors.New("模板不存在")
		return tx
	}
	if len(param) > 0 {
		sql.Param = param[0]
	}
	tx.Statement.MapperItem = sql
	return tx
}

func (db *DB) DOffset(page, limit int) (tx *DB) {
	tx = db.getInstance()
	tx.Statement.MapperItem.Offset = (page - 1) * limit
	tx.Statement.MapperItem.Limit = limit
	return tx
}

// DDelete 获取删除模板
func (db *DB) DDelete(sqlId string, param ...any) (tx *DB) {
	var (
		sql *DynamicNode
		ok  bool
	)
	tx = db.getInstance()
	if sql, ok = tx.Statement.Mapper.Nodes[Delete][sqlId]; !ok {
		tx.Error = errors.New("模板不存在")
		return tx
	}
	if len(param) > 0 {
		sql.Param = param[0]
	}
	tx.Statement.MapperItem = sql
	return tx
}

func (db *DB) DUpdate(sqlId string, param ...any) (tx *DB) {
	var (
		sql *DynamicNode
		ok  bool
	)
	tx = db.getInstance()
	if sql, ok = tx.Statement.Mapper.Nodes[Update][sqlId]; !ok {
		tx.Error = errors.New("模板不存在")
		return tx
	}
	if len(param) > 0 {
		sql.Param = param[0]
	}
	tx.Statement.MapperItem = sql
	return tx
}

func (db *DB) TSelect(value any) (tx *DB) {
	var (
		content string
		vars    []any
		err     error
	)
	tx = db.getInstance()
	if content, vars, err = tx.Statement.MapperItem.Build(); err != nil {
		tx.Error = err
		return tx
	}
	tx.Statement.SQL.WriteString(content)
	tx.Statement.Vars = vars
	tx.Statement.Dest = value
	return tx.callbacks.TQuery().Execute(tx)
}

// TPage 分页查询
func (db *DB) TPage(value any, total *int64) (tx *DB) {
	var (
		content, pageSql, countSql string
		vars                       []any
		countQuery                 = func(db *DB, countSql string, vars []any) (tx *DB) {
			tx = db.getInstance()
			tx.Statement.SQL.WriteString(countSql)
			tx.Statement.Vars = vars
			tx.Statement.Dest = total
			return tx.callbacks.TQuery().Execute(tx)
		}
		pageQuery = func(db *DB, pageSql string, vars []any) (tx *DB) {
			tx = db.getInstance()
			tx.Statement.SQL.WriteString(pageSql)
			tx.Statement.Model = value
			tx.Statement.Vars = vars
			tx.Statement.Dest = value
			return tx.callbacks.TQuery().Execute(tx)
		}
		err error
	)
	tx = db.getInstance()
	if content, vars, err = tx.Statement.MapperItem.Build(); err != nil {
		tx.Error = err
		return tx
	}
	pageSql, countSql, err = utils.SQLParser(content, len(vars))
	// 统计
	tx = countQuery(db, countSql, vars)
	if *total > 0 {
		vars = append(vars, tx.Statement.MapperItem.Offset, tx.Statement.MapperItem.Limit)
		tx = pageQuery(db, pageSql, vars)
	}
	return tx
}

func (db *DB) TUpdate(value any) (tx *DB) {
	var (
		content string
		vars    []any
		err     error
	)
	tx = db.getInstance()
	tx.Statement.MapperItem.Query = value
	if content, vars, err = tx.Statement.MapperItem.Build(); err != nil {
		tx.Error = err
		return tx
	}
	tx.Statement.SQL.WriteString(content)
	tx.Statement.Vars = vars
	return tx.callbacks.TUpdate().Execute(tx)
}

func (db *DB) TDelete() (tx *DB) {
	var (
		content string
		vars    []any
		err     error
	)
	tx = db.getInstance()
	if content, vars, err = tx.Statement.MapperItem.Build(); err != nil {
		tx.Error = err
		return tx
	}
	tx.Statement.SQL.WriteString(content)
	tx.Statement.Vars = vars
	return tx.callbacks.TDelete().Execute(tx)
}

// SQL 获取模板中的SQL
func (db *DB) sql(sqlId, types string, param ...any) (tx *DB) {
	var (
		sql     *DynamicNode
		vars    []any
		content string
		err     error
		ok      bool
	)
	tx = db.getInstance()
	switch types {
	case "select":
		sql, ok = tx.Statement.Mapper.Nodes[Select][sqlId]
	case "update":
		sql, ok = tx.Statement.Mapper.Nodes[Update][sqlId]
	case "insert":
		sql, ok = tx.Statement.Mapper.Nodes[Insert][sqlId]
	case "delete":
		sql, ok = tx.Statement.Mapper.Nodes[Delete][sqlId]
	default:
		tx.Error = errors.New("不支持的SQL类型")
		return tx
	}
	if !ok {
		tx.Error = errors.New("模板不存在")
		return tx
	}
	if len(param) > 0 {
		sql.Param = param[0]
	} else {
		sql.Param = nil
	}
	if content, vars, err = sql.Build(); err != nil {
		tx.Error = err
		return tx
	}
	tx.Statement.SQL.WriteString(content)
	tx.Statement.Vars = vars
	return tx
}
